
#include "masterIncludes.h"
#include "decoder.h"
#include "linkedlist.h"

/*
 *	  _____	   ______  __   __  ______  ______  ______
 *	 /\  __`-./\  __ \ \ \ /\ \ \  ___\/\  ___\ \  __ \
 *	/  \ \ `\ \ \ \_\ \ \ `-.\ \ \ \ ___ \ \__   \ \_\ \
 *   \   \ \  \ \ \  _  \ \      \ \ \\_ \ \  _\   \  __`.
 *	 \	 \ \_/ |  \ \ \ \ \ \`-. \ \ \_\ \ \ \____ \ \ \ \
 *	  \	  \____/   \ \ \_\ \_\  \_\ \_____\ \_____\ \_\ \ \
 *	   \  /   / \  / / / / / /  / / /     / /     / / / / /
 *		\/___/	 \/_/\/_/ /_/ \/_/ /_____/ /_____/ /_/\/_/
 *
 *							DANGER?
 */

unsigned long ulPeriod;
int count = 0;
int flip = 0;
//int readValue = 0;
int qerror[2] = {0, 0};
int qstatus = 0;

int gADCvalue=0;


extern char gUartIndex;
extern char gUartRead;
extern char gUartBuffer[];

extern void UART0IntHandler(void);
extern void UART3IntHandler(void);
extern void UART4IntHandler(void);

void PortUnlock(void);
void initPeripheralClocks(void);
void initTimer4(void);


int main(void) {
	//int generalPurpose=0; //Sir it's general Purpose, you'd better salute!
	int firstRun=1;
	unsigned int temp=0;
	int loop=0;
	int tooMany=0;
	int incrementalExec=0;
	rampdown_condition = 0;
	ramp_hit = 0;
	int temp5=0;

	//used for defining which state we're in, mostly denial
	calibrateState = 0;
	//calibrateState 0 - runtime
	//calibrateState 1 - experimental stats, currently not using it at all
	//calibrateState 2 - pure read out of vals

	//enable clock, 200MHz/5 = 40MHz
	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

	//enable clock, use crystal at 1MHz
	//ROM_SysCtlClockSet(SYSCTL_RCC_XTAL_1MHZ | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

	initPeripheralClocks();

	//unlock PD7 & PF0
	PortUnlock();

	//set up ports and pins
	initGPIO();

	//set up uart for virtual coms and bluetooth and TTS
	initUART();

	welcomeMessage();

	//testing tts module
	initSYN();

	//Timer init has to start after initUART() because it uses bt_UARTsend()
	initTimer0();
	initTimer1();
	initStepper();	//timer 2
	initTimer3();
	initTimer4();

	//init adc
	initADC0();

	//give a delay to settle system
	ROM_SysCtlDelay(10000);

	//init and setup pwm
	initPWM(500);			//keep the driver under 1kHz as per Patrick
	pwmSetDuty(10);

	//enable all interrupts
	ROM_IntMasterEnable();

	if(!QueueInit())
	{
		bt_UARTsend("Init Queue");
		loading_bar(25);
		load_okfail(1);
	}
	else
	{
		bt_UARTsend("Init Queue");
		loading_bar(25);
		load_okfail(0);
	}

	//currently this activates the belt drive... can remove this once the begin routine
	//is set up, which will begin at the push of a button
	belt_driver(0);

	/*
	 * Main Processing Loop
	 * Task:
	 * ADC Sample - Triggered then Timer based?
	 * Poll/Sample Ferromagnetic
	 * StepperPos Set - Stepper control is timer/interrupt based, StepperPos tells it where to go next
	 * LCD Update?
	 */

	//speak welcome
	if(speak_on) SYN_Say((unsigned char *)Volume"歡迎光臨. 你會不會講國語? "); //welcome, do you speak mandarin?
	//if(speak_on) SYN_Say((unsigned char *)Volume"欢迎来到超开心分拣机");


	//print Turn Times
	turnTimes();

	//calibration mechanism
	while(_gStepCalibrate) ROM_SysCtlDelay(500);

	print_list_header();

	//check if calibration for ADC
	if(calibrateState != 0)
	{
		debugHeader();
		bt_UARTsend("Beginning Calibration Run:\r\n");
	}

	//StateChange Resets after loading, some are active low and can trigger
	//state changes prematurely - Delays till states have stabilized
	//ROM_SysCtlDelay(100000);	//Minimum 5mS?
	for ( loop = 0 ; loop < 5 ; loop++)	{ gStateChange[loop]=0; }
	loop=0;

	while(1)
	{
		//readBuff();				//currently dont need to use this
		incrementalExec++;
		/*loop++;
		if (loop >1000000)
		{
			bt_UARTsend("MainLoopMegaTick\r\n ");
			/*temp5 = ROM_TimerValueGet(TIMER4_BASE, TIMER_A);
			temp5=temp5/400000;
			bt_UARTsend("Loop Exec Time: ");
			bt_UARTsend(itoa(temp5,10));
			bt_UARTsend("mS\r\n");
			ROM_TimerLoadSet(TIMER4_BASE, TIMER_A, 0xFFFF);
			loop=0;
			loop=0;
			temp5=0;
		}*/
		//bt_UARTputc('+');
		//check interrupts and do something
		if(calibrateState == 0 || calibrateState == 1)
		{

			if (_gSC && gDC/*DropComplete*/)	//Step is complete
			{
				if (popQueue())		{	_gSC=0;		gDC=0;	_gDrop=0;	sortCount++;}
			}
		}

		if(gStateChange[1])		//reflectometer
		{
			gStateChange[1] = 0;
			//call functions for adc reading here
			int val;
			val = 0;

			if(!gOutput[1] == 0)
			{
				adcReady = 1;
				adcReadCount=0;
				if(rampdown_condition == 1) g_ramp_counter = rampdown_time_common;
			}
			else if(!gOutput[1] == 1)
			{
				if 	(calibrateState == 0)
				{
					//dont use debug print, fucks shit up
					adcReady = 0;
					val = peak_array(adcArr, 1);
					if ( firstRun )
					{
						gDC=1;
						_gSC=1;
						firstRun=0;
						startDelay=30;
					}
					//printReadCount();
				}
				else if (calibrateState == 1)
				{
					/*adcReady = 0;
					printReadCount();
					bt_UARTsend(itoa(calType,10));
					bt_UARTsend(":");
					bt_UARTsend(itoa(calNum,10));
					bt_UARTsend(" ");
					calSet[(calType-1)][(calNum-1)] = peak_array(adcArr,0);
					bt_UARTsend(itoa(calSet[(calType-1)][(calNum-1)],10));
					bt_UARTsend("\r\n");
					calNum--;
					if(calNum == 0)
					{
						calType--;
						calNum = sampNum;
					}
					if(calType == 0) calRng();*/

					adcReady = 0;
					val = calibrate(adcArr, 1);
					if ( firstRun )
					{
						gDC=1;
						_gSC=1;
						firstRun=0;
					}

				}
				else if (calibrateState == 2)
				{
					adcReady = 0;
					//printReadCount();
					val = calibrate(adcArr, 0);

					//else val = peak_array(adcArr, 1);
				}
			}
		}

		if		(calibrateState == 2) {	pwmSetDuty(masterDuty2);	}
		else if (calibrateState == 0) {	pwmSetDuty(masterDuty0);	}
		else						  {	pwmSetDuty(masterDuty1);	}
		//if(calibrateState == 0) debugPrint();		//display interrupt and adc values to console

	}
}


void initPeripheralClocks(void)
{
	// enable PORT A,B,D,E,F GPIO and Timer0 peripheral
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA|SYSCTL_PERIPH_GPIOB|SYSCTL_PERIPH_GPIOC|SYSCTL_PERIPH_GPIOD|SYSCTL_PERIPH_GPIOE|SYSCTL_PERIPH_GPIOF);
	ROM_SysCtlDelay(200000);
}


void UART0IntHandler(void)
{
	unsigned long ulStatus;

	ulStatus = ROM_UARTIntStatus(UART0_BASE, true);
	ROM_UARTIntClear(UART0_BASE, ulStatus);
	while(ROM_UARTCharsAvail(UART0_BASE))
	{
		ROM_UARTCharPutNonBlocking(UART0_BASE, ROM_UARTCharGetNonBlocking(UART0_BASE));
	}
}

void UART3IntHandler(void)
{
	unsigned long ulStatus;

	ulStatus = ROM_UARTIntStatus(UART3_BASE, true);
	ROM_UARTIntClear(UART3_BASE, ulStatus);
	while(ROM_UARTCharsAvail(UART3_BASE))
	{
		ROM_UARTCharPutNonBlocking(UART3_BASE, ROM_UARTCharGetNonBlocking(UART3_BASE));
	}
}

void UART4IntHandler(void)
{
	unsigned long ulStatus;

	ulStatus = ROM_UARTIntStatus(UART4_BASE, true);
	ROM_UARTIntClear(UART4_BASE, ulStatus);
	while(ROM_UARTCharsAvail(UART4_BASE))
	{
		gUartBuffer[gUartIndex]=ROM_UARTCharGetNonBlocking(UART4_BASE);
		gUartIndex++;
		if (gUartIndex > 99) { gUartIndex=0; }
		//ROM_UARTCharPutNonBlocking(UART4_BASE, ROM_UARTCharGetNonBlocking(UART4_BASE));
	}
}

void PortUnlock(void)
{
	//unlock gpio pin PD7 since it's used as a special function
	HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;
	HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;				//PD_7
	HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;

	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;
	HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;				//PF_0
	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
}

void initTimer4(void)
{


	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER4);
	//set timer period: 40MHz/10/2 = 2MHz = 0.5us
	//for 1000us = 1ms use Div by 0.1 and then 4, 40MHz / 0.1 / 4 = 1ms
	ROM_TimerConfigure(TIMER4_BASE, TIMER_CFG_PERIODIC_UP);
	//ulPeriod = (ROM_SysCtlClockGet() / pollFreq);
	ROM_TimerLoadSet(TIMER4_BASE, TIMER_A, 0xffff);

	//Timer interrupt setup
	//ROM_TimerIntClear(TIMER4_BASE, TIMER_TIMA_TIMEOUT);
	//ROM_TimerIntEnable(TIMER4_BASE, TIMER_TIMA_TIMEOUT);
	ROM_IntEnable(INT_TIMER1A);
	ROM_TimerEnable(TIMER4_BASE, TIMER_A);
	bt_UARTsend("Init Timer4");
	loading_bar(24);
	load_okfail(1);


	//memset(gOutput, 0, sizeof(gOutput));
	//memset(gHistory, 0, sizeof(gHistory));
	//memset(gStateChange, 0, sizeof(gStateChange));
}
